﻿using System;

namespace ContextualStateless
{
    public partial class StateMachine< TState, TTrigger, TContext >
    {
        /// <summary>
        /// The configuration for a single state value.
        /// </summary>
        public class StateConfiguration
        {
            #region Attributes
            /// <summary>
            /// State's under configuration representation.
            /// </summary>
            readonly StateRepresentation m_stateRepresentation;

            readonly Func<TState, StateRepresentation> m_lookup;

            /// <summary>
            /// Always satisfied guard method substitution.
            /// </summary>
            static readonly Func< TContext, bool > NoGuard = x => true;

            #endregion

            internal StateConfiguration(StateRepresentation representation, Func<TState, StateRepresentation> lookup)
            {
                m_stateRepresentation = Enforce.ArgumentNotNull(representation, "representation");
                m_lookup = Enforce.ArgumentNotNull(lookup, "lookup");
//                Contract.Requires( representation != null, "representation" );
//                Contract.Requires( lookup != null, "lookup" );
//
//                m_stateRepresentation = representation;
//                m_lookup = lookup;
            }

            // -----------------------------------------------------------------------------------------------------------------

            /// <summary>
            /// Accept the specified trigger and transition to the destination state.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationState">The state that the trigger will cause a
            /// transition to.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>

            public StateConfiguration Permit( TTrigger trigger, TState destinationState, LogicalActionHandler contextHandler = null )
            {
                EnforceNotIdentityTransition( destinationState );

                return InternalPermit( trigger, destinationState, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationState">The state that the trigger will cause a
            /// transition to.</param>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            public StateConfiguration PermitIf( TTrigger trigger, TState destinationState, Func< TContext, bool > guard, LogicalActionHandler contextHandler = null )
            {
                EnforceNotIdentityTransition(destinationState);

                return InternalPermitIf( trigger, destinationState, guard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger, execute exit actions and re-execute entry actions.
            /// Reentry behaves as though the configured state transitions to an identical sibling state.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <remarks>
            /// Applies to the current state only. Will not re-execute superstate actions, or
            /// cause actions to execute transitioning between super- and sub-states.
            /// </remarks>
            public StateConfiguration PermitReentry( TTrigger trigger, LogicalActionHandler contextHandler = null )
            {
                return InternalPermit( trigger, m_stateRepresentation.UnderlyingState, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger, execute exit actions and re-execute entry actions.
            /// Reentry behaves as though the configured state transitions to an identical sibling state.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <remarks>
            /// Applies to the current state only. Will not re-execute superstate actions, or
            /// cause actions to execute transitioning between super- and sub-states.
            /// </remarks>
            public StateConfiguration PermitReentryIf( TTrigger trigger, Func< TContext, bool > guard, LogicalActionHandler contextHandler = null )
            {
                return InternalPermitIf( trigger, m_stateRepresentation.UnderlyingState, guard, contextHandler );
            }

            /// <summary>
            /// Ignore the specified trigger when in the configured state.
            /// </summary>
            /// <param name="trigger">The trigger to ignore.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration Ignore( TTrigger trigger )
            {
                return IgnoreIf( trigger, NoGuard );
            }

            /// <summary>
            /// Ignore the specified trigger when in the configured state, if the guard
            /// returns true..
            /// </summary>
            /// <param name="trigger">The trigger to ignore.</param>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be ignored.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration IgnoreIf( TTrigger trigger, Func< TContext, bool > guard, LogicalActionHandler contextHandler = null )
            {
                Enforce.ArgumentNotNull( guard, "guard" );
                //Contract.Requires( guard != null, "guard" );

                m_stateRepresentation.AddTriggerBehaviour( new UnguardedTriggerRepresentation( trigger, guard, contextHandler ) );
                return this;
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <param name="entryAction">Action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntry(Action entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                return OnEntry(t => entryAction());
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntry(Action<StateTransition> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                m_stateRepresentation.AddEntryAction((t, args) => entryAction(t));
                return this;
            }
            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <param name="entryAction">Action to execute.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom(TTrigger trigger, Action entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                return OnEntryFrom(trigger, t => entryAction());
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom(TTrigger trigger, Action<StateTransition> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                m_stateRepresentation.AddEntryAction(trigger, (t, args) => entryAction(t));
                return this;
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0>( TriggerWithParameters<TArg0> trigger, Action<TArg0> entryAction )
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                return OnEntryFrom(trigger, (a0, t) => entryAction(a0));
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0>(TriggerWithParameters<TArg0> trigger, Action<TArg0, StateTransition> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                Enforce.ArgumentNotNull(trigger, "trigger");
//                Contract.Requires( entryAction != null, "entryAction" );
//                Contract.Requires( trigger != null, "trigger" );

                m_stateRepresentation.AddEntryAction(trigger.Trigger, (t, args) => entryAction( ParameterConversion.Unpack<TArg0>(args, 0), t));

                return this;
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0, TArg1>(TriggerWithParameters<TArg0, TArg1> trigger, Action<TArg0, TArg1> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                return OnEntryFrom(trigger, (a0, a1, t) => entryAction(a0, a1));
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0, TArg1>(TriggerWithParameters<TArg0, TArg1> trigger, Action<TArg0, TArg1, StateTransition> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                Enforce.ArgumentNotNull(trigger, "trigger");
//                Contract.Requires( entryAction != null, "entryAction" );
//                Contract.Requires( trigger != null, "trigger" );

                m_stateRepresentation.AddEntryAction(trigger.Trigger, (t, args) => entryAction(
                    ParameterConversion.Unpack<TArg0>(args, 0),
                    ParameterConversion.Unpack<TArg1>(args, 1), t));

                return this;
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <typeparam name="TArg2">Type of the third trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0, TArg1, TArg2>(TriggerWithParameters<TArg0, TArg1, TArg2> trigger, Action<TArg0, TArg1, TArg2> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                //Contract.Requires( entryAction != null, "entryAction" );

                return OnEntryFrom(trigger, (a0, a1, a2, t) => entryAction(a0, a1, a2));
            }

            /// <summary>
            /// Specify an action that will execute when transitioning into
            /// the configured state.
            /// </summary>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <typeparam name="TArg2">Type of the third trigger argument.</typeparam>
            /// <param name="entryAction">Action to execute, providing details of the transition.</param>
            /// <param name="trigger">The trigger by which the state must be entered in order for the action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnEntryFrom<TArg0, TArg1, TArg2>(TriggerWithParameters<TArg0, TArg1, TArg2> trigger, Action<TArg0, TArg1, TArg2, StateTransition> entryAction)
            {
                Enforce.ArgumentNotNull(entryAction, "entryAction");
                Enforce.ArgumentNotNull(trigger, "trigger");
//                Contract.Requires( entryAction != null, "entryAction" );
//                Contract.Requires( trigger != null, "trigger" );

                m_stateRepresentation.AddEntryAction(trigger.Trigger, (t, args) => entryAction(
                    ParameterConversion.Unpack<TArg0>(args, 0),
                    ParameterConversion.Unpack<TArg1>(args, 1),
                    ParameterConversion.Unpack<TArg2>(args, 2), t));
                return this;
            }

            /// <summary>
            /// Specify an action that will execute when transitioning from
            /// the configured state.
            /// </summary>
            /// <param name="exitAction">Action to execute.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnExit(Action exitAction)
            {
                Enforce.ArgumentNotNull(exitAction, "exitAction");
                //Contract.Requires( exitAction != null, "exitAction" );

                return OnExit(t => exitAction());
            }

            /// <summary>
            /// Specify an action that will execute when transitioning from
            /// the configured state.
            /// </summary>
            /// <param name="exitAction">Action to execute, providing details of the transition.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration OnExit(Action<StateTransition> exitAction)
            {
                Enforce.ArgumentNotNull(exitAction, "exitAction");
                //Contract.Requires( exitAction != null, "exitAction" );

                m_stateRepresentation.AddExitAction(exitAction);
                return this;
            }

            /// <summary>
            /// Sets the superstate that the configured state is a substate of.
            /// </summary>
            /// <remarks>
            /// Substates inherit the allowed transitions of their superstate.
            /// When entering directly into a substate from outside of the superstate,
            /// entry actions for the superstate are executed.
            /// Likewise when leaving from the substate to outside the supserstate,
            /// exit actions for the superstate will execute.
            /// </remarks>
            /// <param name="parentState">The superstate.</param>
            /// <returns>The receiver.</returns>
            public StateConfiguration SubstateOf( TState parentState )
            {
                var _parentState = m_lookup( parentState );

                m_stateRepresentation.SuperState = _parentState;
                _parentState.AddSubstate(m_stateRepresentation);

                return this;
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="stateCalculatingMethod">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            public StateConfiguration PermitDynamic( TTrigger trigger, Func< TContext, TState > stateCalculatingMethod, LogicalActionHandler contextHandler = null )
            {
                return PermitDynamicIf(trigger, stateCalculatingMethod, NoGuard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            public StateConfiguration PermitDynamic< TArg0 >( TriggerWithParameters< TArg0 > trigger, Func< TArg0, TContext, TState > destinationStateSelector, LogicalActionHandler contextHandler = null )
            {
                return PermitDynamicIf( trigger, destinationStateSelector, NoGuard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            public StateConfiguration PermitDynamic< TArg0, TArg1 >( TriggerWithParameters< TArg0, TArg1 > trigger, Func< TArg0, TArg1, TContext, TState > destinationStateSelector, LogicalActionHandler contextHandler = null )
            {
                return PermitDynamicIf( trigger, destinationStateSelector, NoGuard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <typeparam name="TArg2">Type of the third trigger argument.</typeparam>
            public StateConfiguration PermitDynamic<TArg0, TArg1, TArg2>( TriggerWithParameters<TArg0, TArg1, TArg2> trigger, Func<TArg0, TArg1, TArg2, TContext, TState> destinationStateSelector, LogicalActionHandler contextHandler = null )
            {
                return PermitDynamicIf( trigger, destinationStateSelector, NoGuard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="guard">Function that must return true in order for the 
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            public StateConfiguration PermitDynamicIf( TTrigger trigger, Func<TContext, TState> destinationStateSelector, Func<TContext, bool> guard, LogicalActionHandler contextHandler = null )
            {
                Enforce.ArgumentNotNull( destinationStateSelector, "destinationStateSelector" );
                //Contract.Requires( destinationStateSelector != null, "destinationStateSelector" );

                return InternalPermitDynamicIf( trigger, ( args, context ) => destinationStateSelector( context ), guard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            public StateConfiguration PermitDynamicIf<TArg0>( TriggerWithParameters<TArg0> trigger, Func<TArg0, TContext, TState> destinationStateSelector, Func<TContext, bool> guard, LogicalActionHandler contextHandler = null )
            {
                Enforce.ArgumentNotNull( trigger, "trigger" );
                Enforce.ArgumentNotNull( destinationStateSelector, "destinationStateSelector" );
//                Contract.Requires( trigger != null, "trigger" );
//                Contract.Requires( destinationStateSelector != null, "destinationStateSelector" );

                return InternalPermitDynamicIf( trigger.Trigger, ( args, context ) => destinationStateSelector( ParameterConversion.Unpack<TArg0>( args, 0 ), context ),
                    guard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <returns>The reciever.</returns>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            public StateConfiguration PermitDynamicIf<TArg0, TArg1>( TriggerWithParameters<TArg0, TArg1> trigger, Func<TArg0, TArg1, TContext, TState> destinationStateSelector, Func<TContext, bool> guard, LogicalActionHandler contextHandler = null )
            {
                Enforce.ArgumentNotNull( trigger, "trigger" );
                Enforce.ArgumentNotNull( destinationStateSelector, "destinationStateSelector" );
//                Contract.Requires( trigger != null, "trigger" );
//                Contract.Requires( destinationStateSelector != null, "destinationStateSelector" );

                return InternalPermitDynamicIf( trigger.Trigger, ( args, context ) => destinationStateSelector( ParameterConversion.Unpack<TArg0>( args, 0 ), ParameterConversion.Unpack<TArg1>( args, 1 ), context ),
                    guard, contextHandler );
            }

            /// <summary>
            /// Accept the specified trigger and transition to the destination state, calculated
            /// dynamically by the supplied function.
            /// </summary>
            /// <param name="trigger">The accepted trigger.</param>
            /// <param name="destinationStateSelector">Function to calculate the state 
            /// that the trigger will cause a transition to.</param>
            /// <returns>The reciever.</returns>
            /// <param name="guard">Function that must return true in order for the
            /// trigger to be accepted.</param>
            /// <param name="contextHandler">context handler</param>
            /// <typeparam name="TArg0">Type of the first trigger argument.</typeparam>
            /// <typeparam name="TArg1">Type of the second trigger argument.</typeparam>
            /// <typeparam name="TArg2">Type of the third trigger argument.</typeparam>
            public StateConfiguration PermitDynamicIf<TArg0, TArg1, TArg2>( TriggerWithParameters<TArg0, TArg1, TArg2> trigger, Func<TArg0, TArg1, TArg2, TContext, TState> destinationStateSelector, Func<TContext, bool> guard, LogicalActionHandler contextHandler = null )
            {
                Enforce.ArgumentNotNull( trigger, "trigger" );
                Enforce.ArgumentNotNull( destinationStateSelector, "destinationStateSelector" );
//                Contract.Requires( trigger != null, "trigger" );
//                Contract.Requires( destinationStateSelector != null, "destinationStateSelector" );

                return InternalPermitDynamicIf( trigger.Trigger,
                    ( args, context ) => destinationStateSelector(
                        ParameterConversion.Unpack<TArg0>( args, 0 ),
                        ParameterConversion.Unpack<TArg1>( args, 1 ),
                        ParameterConversion.Unpack<TArg2>( args, 2 ), context ),
                    guard, contextHandler );
            }

            protected void EnforceNotIdentityTransition( TState destination )
            {
                //Contract.Requires< ArgumentException >( !destination.Equals( m_stateRepresentation.UnderlyingState ), StateConfigurationResources.SelfTransitionsEitherIgnoredOrReentrant );

                if (destination.Equals(m_stateRepresentation.UnderlyingState))
                    throw new ArgumentException(StateConfigurationResources.SelfTransitionsEitherIgnoredOrReentrant);
            }

            protected StateConfiguration InternalPermit(TTrigger trigger, TState destinationState, LogicalActionHandler contextHandler )
            {
                return InternalPermitIf( trigger, destinationState, x => true, contextHandler );
            }

            protected StateConfiguration InternalPermitIf( TTrigger trigger, TState destinationState, Func< TContext, bool > guard, LogicalActionHandler contextHandler )
            {
                Enforce.ArgumentNotNull(guard, "guard");
                //Contract.Requires( guard != null, "guard" );

                m_stateRepresentation.AddTriggerBehaviour( new GuardedTriggerRepresentation( trigger, destinationState, guard, contextHandler ) );
                return this;                
            }

            [Obsolete( "currently not used" )]
            protected StateConfiguration InternalPermitDynamic(TTrigger trigger, Func<object[], TContext, TState> destinationStateSelector, LogicalActionHandler contextHandler )
            {
                return InternalPermitDynamicIf(trigger, destinationStateSelector, NoGuard, contextHandler );
            }

            protected StateConfiguration InternalPermitDynamicIf( TTrigger trigger, Func< object[], TContext, TState > destinationStateSelector, Func< TContext, bool > guard, LogicalActionHandler contextHandler )
            {
                Enforce.ArgumentNotNull(destinationStateSelector, "destinationStateSelector");
                Enforce.ArgumentNotNull(guard, "guard");
//                Contract.Requires( destinationStateSelector != null, "destinationStateSelector" );
//                Contract.Requires( guard != null, "guard" );

                m_stateRepresentation.AddTriggerBehaviour( new DynamicTriggerRepresentation(trigger, destinationStateSelector, guard, contextHandler ) );
                return this;
            }
        }
    }
}
